package yartiss.engine.simulation.energy.profiles;

import java.util.Arrays;

import yartiss.engine.simulation.IEnergyConsumptionProfile;
import yartiss.engine.simulation.IEnergyProfile;
import yartiss.engine.simulation.energy.profiles.consumption.ConsumptionProfileFactory;
import yartiss.engine.simulation.system.ITask;


public class DefaultEnergyProfile implements IEnergyProfile{


	private final long maxEnergyLevel;
	private final long minEnergyLevel;

	private long currentEnergyLevel;
	private final int powerRate;
	private final long startLevel;

	@Override
	public long getMaxEnergyLevel() {
		return maxEnergyLevel;
	}

	@Override
	public long getMinEnergyLevel() {
		return minEnergyLevel;
	}

	@Override
	public long getCurrentEnergyLevel() {
		return currentEnergyLevel;
	}


	@Override
	public long getPowerRate() {
		return powerRate;
	}


	public DefaultEnergyProfile(int powerRate, long maxEnergyLevel, long minEnergylevel, long startLevel) {
		this.maxEnergyLevel = maxEnergyLevel;
		this.minEnergyLevel = minEnergylevel;
		this.powerRate = powerRate;
		this.currentEnergyLevel = startLevel;
		this.startLevel = startLevel;

	}

	/**
	 * 
	 * @param duration
	 * @param consumption
	 */
	@Override
	public void updateEnergy(long duration, long consumption, long date) {

		currentEnergyLevel -= consumption;
		currentEnergyLevel = Math.min(maxEnergyLevel, duration * powerRate	+ currentEnergyLevel);

		assert currentEnergyLevel >= minEnergyLevel : "energy level fall behind Emin ("+ currentEnergyLevel + ") at time "+date;

	}

	@Override
	public long howLongCanExecute(Iterable<ITask>  tasks) {
		return howLongCanExecute(currentEnergyLevel - minEnergyLevel,  tasks);
	}
	
	@Override
	public long howLongCanExecute(ITask ... tasks) {
		return howLongCanExecute(Arrays.asList(tasks));
	}
	
	@Override
	public long howLongCanExecute(long maxEnergyToConsume, ITask ... tasks) {
		return howLongCanExecute(maxEnergyToConsume, Arrays.asList(tasks));
	}
	
	@Override
	public long howLongCanExecute(long maxEnergyToConsume, Iterable<ITask>  tasks) {
		IEnergyConsumptionProfile cp = consumptionProfile;
		maxEnergyToConsume = Math.min(maxEnergyToConsume, currentEnergyLevel-minEnergyLevel);
		
		
//		for (ITask task : tasks) {
//			if(!isGolobalCons)cp = task.getEnergyConsumptionProfile();
//			long consumptionRate = task.getWcee()/task.getWcet();
//			if (consumptionRate <= powerRate)
//				return Long.MAX_VALUE;
//			return maxEnergyToConsume / (consumptionRate - powerRate);
//		}
		
		long consumed = 0;
		long currentE = currentEnergyLevel;
		long minRomainingcost = Long.MAX_VALUE;
		
		for (ITask task : tasks) {
			if(task.getRemainingCost() < minRomainingcost)
				minRomainingcost = task.getRemainingCost();
		}
		
		for (int i = 0; i < minRomainingcost; i++) {
			for (ITask task : tasks) {
				if(!isGolobalCons)cp = task.getEnergyConsumptionProfile();
				consumed = cp.getConsumed(task.getWcet(), task.getWcee(), i + minRomainingcost, 1);
				currentE += (powerRate - consumed);
				if(currentE < minEnergyLevel){
					return i;
				}
			}
		}
		return minRomainingcost;
	}
		
	@Override
	public void reset() {
		currentEnergyLevel = startLevel;	
	}

	@Override
	public long howMuchCanRecharge(long duration) {
		return duration * powerRate;
	}

	/**
	 * @return the startLevel
	 */
	@Override
	public long getStartEnergyLevel() {
		return startLevel;
	}

	private boolean isGolobalCons = true;
	@Override
	public boolean isGolobalConsumptionProfile() {
		return isGolobalCons;
	}

	@Override
	public void setGolobalConsumptionProfileEnabled(boolean bool) {
		isGolobalCons = bool;
	}

	private IEnergyConsumptionProfile consumptionProfile = ConsumptionProfileFactory.newIntance("default");
	@Override
	public IEnergyConsumptionProfile getGlobalEnergyConsumptionProfile() {
		return consumptionProfile;
	}

	@Override
	public void setGlobalEnergyConsumptionProfile(IEnergyConsumptionProfile p) {
		consumptionProfile = p;
	}

	@Override
	public IEnergyProfile newInstance(int... params) {
		long startLevel = params[1];
		if(params.length >3)
			startLevel = params[3];
		return new DefaultEnergyProfile(params[0], params[1], params[2], startLevel);
	}

	@Override
	public String getName() {
		return "default";
	}
}
